AIDL Hal 开发指南7 —— 实现一个简单的 AIDL HAL

4/9/2024

接下来我们仿造振动器写一个简单的 AIDL HAL 模块。

# AIDL 文件编写

首先,在 hardware/interfaces/ 路径下创建 aidl hal 项目目录:

cd hardware/interfaces
mkdir hello_aidl_hal
cd hello_aidl_hal
mkdir -p android/hardware/hello
1
2
3
4

接着我们在 hardware/interfaces/hello_aidl_hal/aidl/android/hardware/hello 目录下创建 IHelloHal.aidl 文件:

// hardware/interfaces/hello_aidl_hal/aidl/android/hardware/hello/IHelloHal.aidl
package android.hardware.hello;

@VintfStability 
interface IHelloHal {
    void hello_write(String str);
    String hello_read();
}
1
2
3
4
5
6
7
8

接着编写最外层的 Android.bp:

// hardware/interfaces/hello_aidl_hal/aidl/Android.bp
aidl_interface {
    name: "android.hardware.hello",
    vendor_available: true,
    srcs: ["android/hardware/hello/*.aidl"],
    stability: "vintf",
    owner:"xxx.hello",
    backend: {
        cpp: {
            enabled: false,
        },
        java: {
            sdk_version: "module_current",
        },
    },
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

aidl 会生成 java c++ ndk rust 四种库,一般 java 和 ndk 使用会比较多。这部分内容的细节可以在 backend 中配置。

接着就可以编译了:

mmm hardware/interfaces/hello_aidl_hal/
1

报错:

[  7% 186/2361] echo "API dump for the current version of AIDL interface android.hardware.hello does not exist." && echo "Run the co
FAILED: out/soong/.intermediates/hardware/interfaces/hello_aidl_hal/aidl/android.hardware.hello-api/checkapi_current.timestamp
echo "API dump for the current version of AIDL interface android.hardware.hello does not exist." && echo "Run the command \"m android.hardware.hello-update-api\" or add \"unstable: true\" to the build rule for the interface if it does not need to be versioned" && false # hash of input list: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
API dump for the current version of AIDL interface android.hardware.hello does not exist.
Run the command "m android.hardware.hello-update-api" or add "unstable: true" to the build rule for the interface if it does not need to be versioned
15:28:12 ninja failed with: exit status 1
1
2
3
4
5
6

按提示执行:

m android.hardware.hello-update-api
1

执行完成后,生成的代码结构如下:

zzh0838@zzh0838-2204:~/Project/aosp/android-14.0.0_r15$ tree hardware/interfaces/hello_aidl_hal/
hardware/interfaces/hello_aidl_hal/
└── aidl
    ├── aidl_api
    │   └── android.hardware.hello
    │       └── current
    │           └── android
    │               └── hardware
    │                   └── hello
    │                       └── IHelloHal.aidl
    ├── android
    │   └── hardware
    │       └── hello
    │           └── IHelloHal.aidl
    └── Android.bp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

接着再编译:

mmm hardware/interfaces/hello_aidl_hal/
1

执行完成后,就会在 out/soong/.intermediates/hardware/interfaces/hello_aidl_hal/aidl 目录下生成一下的一堆库:

android.hardware.hello-api        android.hardware.hello-V1-java-source  default
android.hardware.hello_interface  android.hardware.hello-V1-ndk
android.hardware.hello-V1-java    android.hardware.hello-V1-ndk-source
1
2
3

# 服务端程序代码编写

接下来在 hardware/interfaces/hello_aidl_hal/aidl/default 目录下创建如下的文件:

20240414095841

hardware/interfaces/hello_aidl_hal/aidl/default/HelloHalImpl.h 实现如下:


#ifndef ANDROID_HARDWARE_HELLO_H
#define ANDROID_HARDWARE_HELLO_H

#include <aidl/android/hardware/hello/BnHelloHal.h>

namespace aidl::android::hardware::hello {

class HelloHalImpl : public BnHelloHal {
  public:
        ::ndk::ScopedAStatus hello_write(const std::string& in_str) override;

        ::ndk::ScopedAStatus hello_read(std::string* _aidl_return) override;
};

}  

#endif  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

hardware/interfaces/hello_aidl_hal/aidl/default/HelloHalImpl.cpp 的实现如下:

#define LOG_TAG "HelloHalImpl"
#define LOG_NDEBUG 0

#include "HelloHalImpl.h"

#include <log/log.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

namespace aidl::android::hardware::hello {


::ndk::ScopedAStatus HelloHalImpl::hello_write(const std::string& in_str) {
    ALOGD("write %s", in_str.c_str());
    int fd;
    int len = in_str.size();
	fd = open("/dev/hello", O_RDWR);
    write(fd, in_str.c_str(), len); 
    close(fd);   
    return ::ndk::ScopedAStatus::ok();
}
  
::ndk::ScopedAStatus HelloHalImpl::hello_read(std::string* _aidl_return)  {
    
    int fd;
    char buf[1024];
	fd = open("/dev/hello", O_RDWR);
    read(fd, buf, 1024);
    *_aidl_return = buf;
    return ::ndk::ScopedAStatus::ok();
}

::ndk::ScopedAStatus HelloHalImpl::hello_init() {
     ALOGD("Hello hal init");
    return ::ndk::ScopedAStatus::ok();
}

}  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

可以看出,这里的 HelloHalImpl 就是 binder 服务端类的具体实现。

接着写一个主程序,来注册这个 binder 服务:

hardware/interfaces/hello_aidl_hal/aidl/default/main.cpp

#include "HelloHalImpl.h"
#define LOG_TAG "HelloHalImpl"
#define LOG_NDEBUG 0
#include <iostream>

#include <android-base/logging.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
#include <stdio.h>
#include <log/log.h>

using aidl::android::hardware::hello::HelloHalImpl;

int main() {
    ABinderProcess_setThreadPoolMaxThreadCount(0);
    std::shared_ptr<HelloHalImpl> hello = ::ndk::SharedRefBase::make<HelloHalImpl>();

    const std::string instance = std::string() + HelloHalImpl::descriptor + "/default";

    ALOGD("HelloHalImpl instance =%s  sde =%p \n", instance.c_str(), hello->asBinder().get());

    binder_status_t status =
          AServiceManager_addService(hello->asBinder().get(), instance.c_str());

    CHECK_EQ(status, STATUS_OK);
    ALOGD("HelloHalImpl AServiceManager_addService status=%d \n", status);
    
    fflush(stdout);
    ABinderProcess_joinThreadPool();
    return EXIT_FAILURE;  // should not reach
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

接着还要写一个 hal 的 vintf:

hardware/interfaces/hello_aidl_hal/aidl/default/hellohal-default.xml

<manifest version="1.0" type="device">
    <hal format="aidl" optional="true">
        <name>android.hardware.hello</name>
        <version>1</version>
        <interface>
        	<name>IHelloHal</name>
        	<instance>default</instance>
    	</interface>
    </hal>
</manifest>
1
2
3
4
5
6
7
8
9
10

需要开机启动,添加:

hardware/interfaces/hello_aidl_hal/aidl/default/android.hardware.hello.rc

service vendor.hellohal-default /vendor/bin/hw/android.hardware.hello.example
    class hal
    user root
    group root
1
2
3
4

接着编写 hardware/interfaces/hello_aidl_hal/aidl/default/Android.bp

cc_binary {
    name: "android.hardware.hello.example",
    relative_install_path: "hw",
    vendor: true,
    init_rc: ["android.hardware.hello.rc"],
    vintf_fragments: ["hellohal-default.xml"],
    shared_libs: [
        "android.hardware.hello-V1-ndk", 
        "liblog",
        "libbase",
        "libcutils",
        "libutils",
        "libbinder_ndk",
    ],
    srcs: [
        "main.cpp",
        "HelloHalImpl.cpp",
    ],
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

接着还需要将 hal 加入到兼容性矩阵中:

hardware/interfaces/compatibility_matrices/compatibility_matrix.8.xml

    <hal format="aidl" optional="true">
        <name>android.hardware.hello</name>
        <version>1</version>
        <interface>
        	<name>IHelloHal</name>
        	<instance>default</instance>
    	</interface>
    </hal>
1
2
3
4
5
6
7
8

在 Android14 中还会多一个叫 fuzzer 的东西,暂时还没搞清楚作用,看源码大部分 hal 都没有做支持,这里我们写的 hal 也不做支持,修改 system/sepolicy/build/soong/service_fuzzer_bindings.go :

        "android.hardware.vibrator.IVibrator/default":                             EXCEPTION_NO_FUZZER,
		"android.hardware.vibrator.IVibratorManager/default":                      []string{"android.hardware.vibrator-service.example_fuzzer"},
        // 添加的内容
		"android.hardware.hello.IHelloHal/default":                      		   EXCEPTION_NO_FUZZER,
		"android.hardware.weaver.IWeaver/default":                                 EXCEPTION_NO_FUZZER,
1
2
3
4
5

# Selinux

接下来配置 Selinux 权限:

添加 system/sepolicy/vendor/hal_hello.te

hal_attribute(hellohal);
type hal_hellohal_default, domain, mlstrustedsubject;
hal_server_domain(hal_hellohal_default, hal_hellohal);
type hal_hellohal_default_exec, exec_type, vendor_file_type, file_type;
init_daemon_domain(hal_hellohal_default);

binder_call(hal_hellohal_client, hal_hellohal_default)

type hal_hellohal_service, service_manager_type;
add_service(hal_hellohal_default, hal_hellohal_service)
allow hal_hellohal_client hal_hellohal_service:service_manager find;
hal_client_domain(system_server, hal_hellohal)

allow hal_hellohal_default servicemanager:binder { call transfer };
allow {  platform_app shell } hal_hellohal:binder {call};

allow hal_hellohal_default hello_dev_t:chr_file { open read write }; 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

system/sepolicy/vendor/file_contexts 中添加:

/(vendor|system/vendor)/bin/hw/android\.hardware\.hello\.example         	 u:object_r:hal_hellohal_default_exec:s0
1

修改 system/sepolicy/private/service_contextssystem/sepolicy/prebuilts/api/34.0/private/service_contexts,注意保持两个文件一致:

android.hardware.hello.IHelloHal/default                  	         u:object_r:hal_hellohal_service:s0
1

# 编写测试程序

hardware/interfaces/hello_aidl_hal 目录下创建:

20240414104625

hardware/interfaces/hello_aidl_hal/test_aidl_hal/main.cpp:

#define LOG_TAG "Test-HAL"
#define LOG_NDEBUG 0
#include <iostream>

#include <log/log.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
#include <aidl/android/hardware/hello/IHelloHal.h>

#include <stdio.h>
using aidl::android::hardware::hello::IHelloHal;

int main() {
    std::shared_ptr<IHelloHal> service = IHelloHal::fromBinder(ndk::SpAIBinder(AServiceManager_getService("android.hardware.hello.IHelloHal/default")));
    ALOGD("get service = %p\n",service.get());

    if (service == nullptr) {
        return -1;
    }
    service->hello_write("hello");
    fflush(stdout);
    return EXIT_FAILURE;  // should not reach
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

hardware/interfaces/hello_aidl_hal/test_aidl_hal/Android.bp:

cc_binary {
    name: "test_aidl_hal",
    vendor: true,
    shared_libs: [
        "android.hardware.hello-V1-ndk", 
        "liblog",
        "libbase",
        "libcutils",
        "libutils",
        "libbinder_ndk",
    ],
    srcs: [
        "main.cpp",
    ],
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 编译与测试

# 编译
source build/envsetup.sh
lunch aosp_cf_x86_phone-eng
m
# 启动模拟器
cvd start  -kernel_path=/home/zzh0838/Project/aosp/kernel/out/virtual_device_x86_64/dist/bzImage  -initramfs_path=/home/zzh0838/Project/aosp/kernel/out/virtual_device_x86_64/dist/initramfs.img
1
2
3
4
5
6

最后测试,

运行测试程序:

adb shell
test_aidl_hal 
1
2

查看 log:

adb logcat | grep hello
04-11 11:13:31.414     0     0 W         : drivers/char/hello_driver.c hello_init line 69
04-11 11:13:32.803     0     0 I init    : Parsing file /vendor/etc/init/android.hardware.hello.rc...
04-11 11:13:37.533     0     0 I init    : starting service 'vendor.hellohal-default'...
04-11 11:13:37.537     0     0 I init    : ... started service 'vendor.hellohal-default' has pid 339
04-11 11:13:37.604     0     0 I servicemanager: Found android.hardware.hello.IHelloHal/default in device VINTF manifest.
04-11 11:20:11.512   339   339 D HelloHalImpl: write hello
1
2
3
4
5
6
7

# 参考资料